"""Module responsible for movement analysis"""
from numpy import zeros, uint8
from PIL import Image, ImageTk, ImagePath, ImageDraw
from collections import deque
import params
#from time import clock

class Hands():
    """Class containing both hands and handling updates and display of traces/gesture"""
    def __init__(self):
        self.leftHand = Status()
        self.rightHand = Status()
    
    def update(self, leftStatus, rightStatus):
        """Use to update hands status'"""
        self.leftHand.updateStatus(leftStatus)
        self.rightHand.updateStatus(rightStatus)
           
    def getTraceImage(self):
        """Returns QPixmap image with marked traces - two colors"""
        traceImage = zeros((480, 640, 3), uint8)
        leftTrace = list(self.leftHand.trace.getTrace())
        rightTrace = list(self.rightHand.trace.getTrace())
        
        # draw color points of trace
        for points in leftTrace:
            traceImage[points[0]][points[1]][0] = 255
                       
        for points in rightTrace:
            traceImage[points[0]][points[1]][1] = 255
                      
        traceImage = Image.fromarray(traceImage, mode = 'RGB')
        
        # draw lines connecting finished gesture points
        leftGesture = self.leftHand.gesture.getGesture()
        if leftGesture:     
            imPath = ImagePath.Path(leftGesture)
            draw = ImageDraw.Draw(traceImage)
            draw.line(imPath, fill = "red", width = 3)
        
        rightGesture = self.rightHand.gesture.getGesture()
        if rightGesture:     
            imPath = ImagePath.Path(rightGesture)
            draw = ImageDraw.Draw(traceImage)
            draw.line(imPath, fill = "green", width = 3)
        return traceImage

class Status():
    """Parent class for one-hand gesture"""
    def __init__(self, statusHistoryLength = params.MAX_STATUS_HISTORY):
        self.statusQueue = deque([], statusHistoryLength)
        self.trace = Trace()
        self.movement = Movement()
        self.gesture = Gesture()
    
    def updateStatus(self, currentStatus):
        """Update status and check for folding/unfolding, steering of Gesture class work"""
        self.statusQueue.append(currentStatus)
        self.trace.updateTrace(currentStatus["hand_center"])
        areaChange = self.movement.updateArea(currentStatus["hand_area"]) 
                   
        if self.movement.isFolded():
            if areaChange == "folded":
                self.gesture.resetPath()            
            self.gesture.updatePath(currentStatus["hand_center"])
            self.gesture.updatePath(currentStatus["hand_center"])
        elif areaChange == "unfolded":
            self.gesture.saveGesture()
            self.gesture.resetPath()
            #TODO: powiadomic o wykonaniu i zakonczeniu gestu

                   
class Trace():
    """Class containing trace of hands movement and appropriate methods for handling those traces"""
    def __init__(self, maxPoints = params.MAX_TRACE_POINTS):
        """Initialization with maximum number of points to be preserved"""
        self.traceQueue = deque([], maxPoints)
        
    def updateTrace(self, centerPoint):    
        """Updates trace with new points"""    
        self.traceQueue.append(centerPoint)       
                
    def resetTrace(self):
        self.traceQueue.clear() 
        
    def getTrace(self):
        return self.traceQueue
           
class Movement():
    """Class responsible for detecting gesture and its analysis"""
    def __init__(self, statusHistoryLength = params.MAX_STATUS_HISTORY):
        self.areaQueue = deque([], statusHistoryLength)
        self.folded = False
        
    def detectFold(self):
        currElem = list(self.areaQueue)[-1] * params.FOLD_FRACTION
        for historyElem in list(self.areaQueue)[-params.HISTORY_FRAMES_TO_USE:-1]:
            if currElem < historyElem:
                return True
        return False
    
    def detectUnfold(self):
        currElem = list(self.areaQueue)[-1] / params.FOLD_FRACTION
        for historyElem in list(self.areaQueue)[-params.HISTORY_FRAMES_TO_USE:-1]:
            if currElem > historyElem:
                return True
        return False
    
    def updateArea(self, currArea):
        """Updates area queue and detects folding/unfolding, sets folded parameter accordingly"""
        self.areaQueue.append(currArea)
        if self.folded:
            if self.detectUnfold():
                self.folded = False
                return "unfolded"
        elif self.detectFold():
            self.folded = True
            return "folded"
        
    def isFolded(self):
        return self.folded

class Gesture():
    """Class responsible for storing, analyzing and adding new gestures"""
    def __init__(self, maxGestureLength = params.MAX_GESTURE_LENGTH):
        self.pathQueue = deque([], maxGestureLength)
        self.gesturePath = None
    
    def updatePath(self, currPoint):
        self.pathQueue.append(currPoint)
    
    def resetPath(self):
        self.pathQueue.clear()
        
    def getGesture(self):
        """Returns gesture path as a list of tuples of both coordinates, suitable for ImagePath"""
        if self.gesturePath:
            return [(el[1], el[0]) for el in self.gesturePath]
        else:
            return None
    
    def saveGesture(self):
        """Invoked when gesture is finished, saves final gesture path to gesturePath list"""
        self.gesturePath = list(self.pathQueue)
    
